By default, XNA for Windows Phone is set up for a landscape orientation,
perhaps to be compatible with other screens on which games are played.
Both landscape orientations are supported, and the display will
automatically flip around when you turn the phone from one landscape
orientation to the other. If you prefer designing your game for a portrait display, it’s easy to do that. In the constructor of the Game1 class of XnaHelloPhone, try inserting the following statements:
graphics.PreferredBackBufferWidth = 320;
graphics.PreferredBackBufferHeight = 480;
The back buffer is the surface area on which XNA constructs the graphics you display in the Draw
method. You can control both the size and the aspect ratio of this
buffer. Because the buffer width I’ve specified here is smaller than the
buffer height, XNA assumes that I want a portrait display:
Look at that! The back buffer I specified is not the same aspect ratio as the Windows Phone 7 display, so the drawing
surface is letter-boxed! The text is larger because it’s the same pixel
size but now the display resolution has been reduced.
Although you may not be a big
fan of the retro graininess of this particular display, you should
seriously consider specifying a smaller back buffer if your game doesn’t need the high resolution provided by the phone. Performance will improve and battery
consumption will decrease. You can set the back buffer to anything from
240 x 240 up to 480 x 800 (for portrait mode) or 800 x 480 (for
landscape). XNA uses the aspect ratio to determine whether you want portrait or landscape.
Setting a desired back buffer
is also an excellent way to target a specific display dimension in code
but allow for devices of other sizes that may come in the future.
By default
the back buffer is 800 x 480, but it’s actually not displayed at that
size. It’s scaled down a bit to accommodate the system tray. To get rid
of the system tray (and possibly annoy your users who like to always
know what time it is) you can set
graphics.IsFullScreen = true;
in the Game1 constructor.
It’s also possible to have your XNA games respond to orientation changes, but they’ll definitely have to be restructured a bit. The simplest type of restructuring to accommodate orientation changes is demonstrated in the XnaOrientableHelloPhone project. The fields now include a textSize variable:
Example 1. XNA Project: XnaOrientableHelloPhone File: Game1.cs (excerpt showing fields)
public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; string text = "Hello, Windows Phone 7!"; SpriteFont segoe14; Vector2 textSize; Vector2 textPosition; . . . }
|
The Game1 constructor includes a statement that sets the SupportedOrientations property of the graphics field:
Example 2. XNA Project: XnaOrientableHelloPhone File: Game1.cs (excerpt)
public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content";
// Allow portrait mode as well graphics.SupportedOrientations = DisplayOrientation.Portrait | DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
// Frame rate is 30 fps by default for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks(333333); }
|
You can also use SupportedOrientation to restrict the phone to just one of the two landscape orientations. The statement to support both portrait and landscape looks simple, but there are repercussions. When the orientation
changes, the graphics device is effectively reset (which generates some
events) and the back buffer dimensions are swapped. You can subscribe
to the OrientationChanged event of the GameWindow class (accessible through the Window property) or you can check the CurrentOrientation property of the GameWindow object.
I chose a little different approach. Here’s the new LoadContent method, which you’ll notice obtains the text size and stores it as a field, but does not get the viewport.
Example 3. XNA Project: XnaOrientableHelloPhone File: Game1.cs (excerpt)
protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); segoe14 = this.Content.Load<SpriteFont>("Segoe14"); textSize = segoe14.MeasureString(text); }
|
Instead, the viewport is obtained during the Update method because the dimensions of the viewport reflect the orientation of the display.
Example 4. XNA Project: XnaOrientableHelloPhone File: Game1.cs (excerpt)
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();
Viewport viewport = this.GraphicsDevice.Viewport; textPosition = new Vector2((viewport.Width - textSize.X) / 2, (viewport.Height - textSize.Y) / 2); base.Update(gameTime); }
|
Whatever the orientation currently is, the Update method calculates a location for the text. The Draw method is the same as several you’ve seen before.
Example 2-11. XNA Project: XnaOrientableHelloPhone File: Game1.cs (excerpt)
protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.Navy);
spriteBatch.Begin(); spriteBatch.DrawString(segoe14, text, textPosition, Color.White); spriteBatch.End();
base.Draw(gameTime); }
|
Now the phone or emulator can be turned between portrait and landscape, and the display will switch as well.
If you need to obtain the size
of the phone’s display independent of any back buffers or orientation
(but taking account of the system tray), that’s available from the ClientBounds property of the GameWindow class, which you can access from the Window property of the Game class: